package com.seuic.device_implement;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.seuic.android.ICCardReader;
import com.seuic.android.Pinpad;
import com.seuic.android.PosdService;
import com.seuic.android.Printer;
import com.seuic.android.SuperPinpad;
import com.seuic.extra.emv.EmvFuncs;
import com.seuic.extra.psam.IPsamReader;
import com.seuic.extra.receipt.Receipt;
import com.seuic.posdsdk.device_interface.EmvDevice;
import com.seuic.posdsdk.device_interface.PinpadDevice;
import com.seuic.posdsdk.device_interface.PosDevice;
import com.seuic.posdsdk.device_interface.PrinterDevice;
import com.seuic.posdsdk.device_interface.PsamDevice;
import com.seuic.posdsdk.device_interface.ReceiptEngine;

import java.util.List;

public class PosDeviceImp extends BaseImplement implements PosDevice {

    private static final String LOG_TAG = "PosdSdk";
    private static PosDeviceImp self;

    private PosDeviceImp() {

    }

    public static PosDeviceImp getInstace() {
        if ( self == null ) {
            synchronized (PosDeviceImp.class) {
                if (self == null) {
                    self = new PosDeviceImp();
                }
            }
        }
        return self;
    }

    private static final String POSD_SERVIVCE_INTENT = "com.seuic.android.PosdService";
    private Context context;
    private String posdServicePackageName = null;
    private PosdServiceConnection posdServiceConnection;

    @Override
    public int init(Context context) {
        if ( this.context != null && posdService != null ) {
            return 0;
        }
        if ( context == null ) {
            return -1;
        }
        this.context = context.getApplicationContext();
        bindPosdService();
        return 0;
    }

    private String getPosdServicePackageName() {
        if ( posdServicePackageName != null ) {
            return posdServicePackageName;
        }
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> list = pm.queryIntentServices( new Intent( POSD_SERVIVCE_INTENT ), 0 );
        //LogInfo( "PosdService List: " + list );
        if ( list == null || list.isEmpty() ) {
            return "com.seuic.android";
        }
        ResolveInfo info = list.get(0);
        posdServicePackageName = info.serviceInfo.packageName;
        return posdServicePackageName;
    }

    private void bindPosdService() {
        Intent intent = new Intent();
        intent.setAction( POSD_SERVIVCE_INTENT );
        intent.setPackage( getPosdServicePackageName() );
        posdServiceConnection = new PosdServiceConnection();
        context.bindService( intent, posdServiceConnection, Context.BIND_AUTO_CREATE );
    }

    private class PosdServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            posdService = PosdService.Stub.asInterface( service );
            if ( posdService != null ) {
                try {
                    pinpad = Pinpad.Stub.asInterface(posdService.getPinpad());
                    superPinpad = SuperPinpad.Stub.asInterface(posdService.getSuperPinpad());
                    printer = Printer.Stub.asInterface(posdService.getPrinter());
                    receipt = Receipt.Stub.asInterface(posdService.getExtraFuncs("Receipt"));
                    icCardReader = ICCardReader.Stub.asInterface( posdService.getICCardReader() );
                    emvFuncs = EmvFuncs.Stub.asInterface( posdService.getExtraFuncs( "EMV" ));
                    psamReader = IPsamReader.Stub.asInterface(posdService.getExtraFuncs( "PsamReader" ));
                } catch (RemoteException e) {
                    Log.e( LOG_TAG, "RemoteException: " + e );
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }

        @Override
        public void onBindingDied(ComponentName name) {
            context.unbindService( posdServiceConnection );
            bindPosdService();
        }
    }

    @Override
    public void close() {
        if ( context != null && posdServiceConnection != null ) {
            context.unbindService( posdServiceConnection );
            context = null;
            posdServiceConnection = null;
            clearDeviceInterface();
        }
    }

    @Override
    public String getTermSerial() {
        if ( posdService == null ) {
            setLastError( "Service Error" );
            return null;
        }
        try {
            return posdService.getTermSerial();
        } catch (RemoteException e) {
            Log.e( LOG_TAG, "RemoteException: " + e );
            setLastError( "Service RemoteException: " + e );
            return null;
        }
    }

    @Override
    public String getSystemVersion() {
        if ( posdService == null ) {
            setLastError( "Service Error" );
            return null;
        }
        try {
            return posdService.getSystemVersion();
        } catch (RemoteException e) {
            Log.e( LOG_TAG, "RemoteException: " + e );
            setLastError( "Service RemoteException: " + e );
            return null;
        }
    }

    @Override
    public String getProductModel() {
        if ( posdService == null ) {
            setLastError( "Service Error" );
            return null;
        }
        try {
            return posdService.getProductModel();
        } catch (RemoteException e) {
            Log.e( LOG_TAG, "RemoteException: " + e );
            setLastError( "Service RemoteException: " + e );
            return null;
        }
    }

    @Override
    public String getServiceVersion() {
        if ( posdService == null ) {
            setLastError( "Service Error" );
            return null;
        }
        try {
            return posdService.getServiceName();
        } catch (RemoteException e) {
            Log.e( LOG_TAG, "RemoteException: " + e );
            setLastError( "Service RemoteException: " + e );
            return null;
        }
    }

    @Override
    public PinpadDevice getPinpad() {
        return PinpadDeviceImp.getInstance();
    }

    @Override
    public EmvDevice getEmv() {
        return EmvDeviceImp.getInstance();
    }

    @Override
    public ReceiptEngine getReceiptEngin() {
        return ReceiptEngineImp.getInstance();
    }

    @Override
    public PrinterDevice getPrinter() {
        return PrinterDeviceImp.getInstance();
    }

    @Override
    public PsamDevice getPsamDevice() {
        return PsamDeviceImp.getInstance();
    }

}
